<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en-US">
<head>
    <meta charset="utf-8">


    <link href="/assets/css/all.css" rel="stylesheet" type="text/css">
    <script async src="/assets/js/all.js"></script>


    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({tex2jax: {inlineMath: [['«', '»']]}});
      MathJax.Hub.config.tex2jax.skipTags = ["script", "noscript", "style", "textarea", "annotation", "annotation-xml"];

    </script>
    <script async src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/MathJax.js?config=TeX-AMS_HTML'></script>
    <!-- Google Analytics -->
    <script>
        window.ga = window.ga || function () {
            (ga.q = ga.q || []).push(arguments)
        };
        ga.l = +new Date;
        ga('create', 'UA-58002512-1', 'auto');
        ga('set', 'anonymizeIp', true);
        ga('send', 'pageview');
    </script>
    <script async src='https://www.google-analytics.com/analytics.js'></script>
    <!-- End Google Analytics -->

    <title>Nim by Example - Macros</title>

    <meta content="nanoc 4.9.9" name="generator">
    <meta content="colorful" http-equiv="Default-Style">
    <meta content="width=device-width, initial-scale=1" name=viewport>
</head>
<body>

<div id="sidebar">
    <div class="abs-hamburger">
        <div class="nav-toggle" onclick="sidebarClick();"><span></span></div>
    </div>
    <nav>
        <ul>
            <li><a href="/getting_started/">Getting Started</a></li>
            <li><a href="/hello_world/">Hello World</a></li>
            <li><a href="/comments/">Comments</a></li>
            <li><a href="/variables/">Variables</a>
                <ul>
                    <li><a href="/variables/result/">Result</a></li>
                    <li><a href="/variables/type_casting_inference/">Type Casting and Inference</a></li>
                </ul>
            </li>
            <li><a href="/if_else_while/">If, Else, While</a></li>
            <li><a href="/case/">Case Statements</a></li>
            <li><a href="/for_iterators/">For Loops &amp; Iterators</a></li>
            <li><a href="/procs/">Procs</a></li>
            <li><a href="/procvars/">First Class Functions</a></li>
            <li><a href="/block/">Blocks</a></li>
            <li><a href="/primitives/">Primitive Types</a></li>
            <li><a href="/types/">Type Aliases</a></li>
            <li><a href="/types/objects/">Object Types</a></li>
            <li><a href="/types/enums/">Enum Types</a></li>
            <li><a href="/types/distinct/">Distinct Types</a></li>
            <li><a href="/strings/">Strings</a></li>
            <li><a href="/arrays/">Arrays</a></li>
            <li><a href="/seqs/">Seqs</a></li>
            <li><a href="/bitsets/">Bitsets</a></li>
            <li><a href="/files/">Files</a></li>
            <li><a href="/json/">JSON</a></li>
            <li><a href="/varargs/">Varargs</a></li>
            <li><a href="/oop/">Object Oriented Programming</a></li>
            <li><a href="/macros/">Macros</a></li>
        </ul>


    </nav>
</div>

<article>
    <!--- Thanks to fowl for creating this page, filwit for fixing some oddities -->

    <h1 id="macros">Macros</h1>

    <p>Nim’s syntax is incredibly versatile, and macros can be used to rewrite the abstract syntax tree of a program.
        The general process for writing a macro consists of two steps that are repeated until the desired results are
        achieved:</p>

    <ol>
        <li>Dump and examine the AST</li>
        <li>Modify the AST to match the desired shape</li>
    </ol>

    <p>The example shown here describes how to create new class syntax in Nim, purely through a library.</p>

    <p>This is the code that we currently must write to use OOP in Nim:</p>

    <pre><code class="language-nimrod"><span class="k">type</span> <span class="n">Animal</span> <span
            class="o">=</span> <span class="k">ref</span> <span class="k">object</span> <span class="k">of</span> <span
            class="n">RootObj</span>
  <span class="n">name</span><span class="p">:</span> <span class="kt">string</span>
  <span class="n">age</span><span class="p">:</span> <span class="kt">int</span>
<span class="k">method</span> <span class="n">vocalize</span><span class="p">(</span><span class="n">self</span><span
                class="p">:</span> <span class="n">Animal</span><span class="p">):</span> <span class="kt">string</span> <span
                class="p">{.</span><span class="n">base</span><span class="p">.}</span> <span class="o">=</span> <span
                class="s">"..."</span>
<span class="k">method</span> <span class="n">ageHumanYrs</span><span class="p">(</span><span class="n">self</span><span
                class="p">:</span> <span class="n">Animal</span><span class="p">):</span> <span
                class="kt">int</span> <span class="p">{.</span><span class="n">base</span><span
                class="p">.}</span> <span class="o">=</span> <span class="n">self</span><span class="p">.</span><span
                class="n">age</span>

<span class="k">type</span> <span class="n">Dog</span> <span class="o">=</span> <span class="k">ref</span> <span
                class="k">object</span> <span class="k">of</span> <span class="n">Animal</span>
<span class="k">method</span> <span class="n">vocalize</span><span class="p">(</span><span class="n">self</span><span
                class="p">:</span> <span class="n">Dog</span><span class="p">):</span> <span
                class="kt">string</span> <span class="o">=</span> <span class="s">"woof"</span>
<span class="k">method</span> <span class="n">ageHumanYrs</span><span class="p">(</span><span class="n">self</span><span
                class="p">:</span> <span class="n">Dog</span><span class="p">):</span> <span class="kt">int</span> <span
                class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">age</span> <span
                class="o">*</span> <span class="mi">7</span>

<span class="k">type</span> <span class="n">Cat</span> <span class="o">=</span> <span class="k">ref</span> <span
                class="k">object</span> <span class="k">of</span> <span class="n">Animal</span>
<span class="k">method</span> <span class="n">vocalize</span><span class="p">(</span><span class="n">self</span><span
                class="p">:</span> <span class="n">Cat</span><span class="p">):</span> <span
                class="kt">string</span> <span class="o">=</span> <span class="s">"meow"</span></code></pre>

    <p>All these typedefs and <code>self: T</code> parameters are repetitive, so it’d be good to write a macro to mask
        them. Something like this would be nice:</p>

    <pre><code class="language-nimrod"><span class="n">class</span> <span class="n">Animal</span> <span
            class="k">of</span> <span class="n">RootObj</span><span class="p">:</span>
  <span class="kd">var</span> <span class="n">name</span><span class="p">:</span> <span class="kt">string</span>
  <span class="kd">var</span> <span class="n">age</span><span class="p">:</span> <span class="kt">int</span>
  <span class="k">method</span> <span class="n">vocalize</span><span class="p">:</span> <span
                class="kt">string</span> <span class="o">=</span> <span class="s">"..."</span>
  <span class="k">method</span> <span class="n">age_human_yrs</span><span class="p">:</span> <span class="kt">int</span> <span
                class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">age</span>  <span
                class="c"># `self` is injected</span>

<span class="n">class</span> <span class="n">Dog</span> <span class="k">of</span> <span class="n">Animal</span><span
                class="p">:</span>
  <span class="k">method</span> <span class="n">vocalize</span><span class="p">:</span> <span
                class="kt">string</span> <span class="o">=</span> <span class="s">"woof"</span>
  <span class="k">method</span> <span class="n">age_human_yrs</span><span class="p">:</span> <span class="kt">int</span> <span
                class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">age</span> <span
                class="o">*</span> <span class="mi">7</span>

<span class="n">class</span> <span class="n">Cat</span> <span class="k">of</span> <span class="n">Animal</span><span
                class="p">:</span>
  <span class="k">method</span> <span class="n">vocalize</span><span class="p">:</span> <span
                class="kt">string</span> <span class="o">=</span> <span class="s">"meow"</span></code></pre>

    <p>To get that nice notation, we can use a macro:</p>

    <pre><code class="language-nimrod"><span class="kn">import</span> <span class="n">macros</span>

<span class="k">macro</span> <span class="n">class</span><span class="o">*</span><span class="p">(</span><span
                class="n">head</span><span class="p">,</span> <span class="n">body</span><span class="p">:</span> <span
                class="n">untyped</span><span class="p">):</span> <span class="n">untyped</span> <span
                class="o">=</span>
  <span class="c"># The macro is immediate, since all its parameters are untyped.</span>
  <span class="c"># This means, it doesn't resolve identifiers passed to it.</span>

  <span class="kd">var</span> <span class="n">typeName</span><span class="p">,</span> <span
                class="n">baseName</span><span class="p">:</span> <span class="n">NimNode</span>

  <span class="c"># flag if object should be exported</span>
  <span class="kd">var</span> <span class="n">isExported</span><span class="p">:</span> <span class="kt">bool</span>

  <span class="k">if</span> <span class="n">head</span><span class="p">.</span><span class="n">kind</span> <span
                class="o">==</span> <span class="n">nnkInfix</span> <span class="ow">and</span> <span
                class="n">eqIdent</span><span class="p">(</span><span class="n">head</span><span class="o">[</span><span
                class="mi">0</span><span class="o">]</span><span class="p">,</span> <span class="s">"of"</span><span
                class="p">):</span>
    <span class="c"># `head` is expression `typeName of baseClass`</span>
    <span class="c"># echo head.treeRepr</span>
    <span class="c"># --------------------</span>
    <span class="c"># Infix</span>
    <span class="c">#   Ident !"of"</span>
    <span class="c">#   Ident !"Animal"</span>
    <span class="c">#   Ident !"RootObj"</span>
    <span class="n">typeName</span> <span class="o">=</span> <span class="n">head</span><span class="o">[</span><span
                class="mi">1</span><span class="o">]</span>
    <span class="n">baseName</span> <span class="o">=</span> <span class="n">head</span><span class="o">[</span><span
                class="mi">2</span><span class="o">]</span>

  <span class="k">elif</span> <span class="n">head</span><span class="p">.</span><span class="n">kind</span> <span
                class="o">==</span> <span class="n">nnkInfix</span> <span class="ow">and</span> <span
                class="n">eqIdent</span><span class="p">(</span><span class="n">head</span><span class="o">[</span><span
                class="mi">0</span><span class="o">]</span><span class="p">,</span> <span class="s">"*"</span><span
                class="p">)</span> <span class="ow">and</span>
       <span class="n">head</span><span class="o">[</span><span class="mi">2</span><span class="o">]</span><span
                class="p">.</span><span class="n">kind</span> <span class="o">==</span> <span class="n">nnkPrefix</span> <span
                class="ow">and</span> <span class="n">eqIdent</span><span class="p">(</span><span
                class="n">head</span><span class="o">[</span><span class="mi">2</span><span class="o">][</span><span
                class="mi">0</span><span class="o">]</span><span class="p">,</span> <span class="s">"of"</span><span
                class="p">):</span>
    <span class="c"># `head` is expression `typeName* of baseClass`</span>
    <span class="c"># echo head.treeRepr</span>
    <span class="c"># --------------------</span>
    <span class="c"># Infix</span>
    <span class="c">#   Ident !"*"</span>
    <span class="c">#   Ident !"Animal"</span>
    <span class="c">#   Prefix</span>
    <span class="c">#     Ident !"of"</span>
    <span class="c">#     Ident !"RootObj"</span>
    <span class="n">typeName</span> <span class="o">=</span> <span class="n">head</span><span class="o">[</span><span
                class="mi">1</span><span class="o">]</span>
    <span class="n">baseName</span> <span class="o">=</span> <span class="n">head</span><span class="o">[</span><span
                class="mi">2</span><span class="o">][</span><span class="mi">1</span><span class="o">]</span>
    <span class="n">isExported</span> <span class="o">=</span> <span class="kp">true</span>

  <span class="k">else</span><span class="p">:</span>
    <span class="n">error</span> <span class="s">"Invalid node: "</span> <span class="o">&amp;</span> <span class="n">head</span><span
                class="p">.</span><span class="n">lispRepr</span>

  <span class="c"># The following prints out the AST structure:</span>
  <span class="c">#</span>
  <span class="c"># import macros</span>
  <span class="c"># dumptree:</span>
  <span class="c">#   type X = ref object of Y</span>
  <span class="c">#     z: int</span>
  <span class="c"># --------------------</span>
  <span class="c"># StmtList</span>
  <span class="c">#   TypeSection</span>
  <span class="c">#     TypeDef</span>
  <span class="c">#       Ident !"X"</span>
  <span class="c">#       Empty</span>
  <span class="c">#       RefTy</span>
  <span class="c">#         ObjectTy</span>
  <span class="c">#           Empty</span>
  <span class="c">#           OfInherit</span>
  <span class="c">#             Ident !"Y"</span>
  <span class="c">#           RecList</span>
  <span class="c">#             IdentDefs</span>
  <span class="c">#               Ident !"z"</span>
  <span class="c">#               Ident !"int"</span>
  <span class="c">#               Empty</span>

  <span class="c"># create a new stmtList for the result</span>
  <span class="n">result</span> <span class="o">=</span> <span class="n">newStmtList</span><span class="p">()</span>

  <span class="c"># create a type section in the result</span>
  <span class="k">template</span> <span class="n">typeDecl</span><span class="p">(</span><span class="n">a</span><span
                class="p">,</span> <span class="n">b</span><span class="p">):</span> <span
                class="n">untyped</span> <span class="o">=</span>
    <span class="k">type</span> <span class="n">a</span> <span class="o">=</span> <span class="k">ref</span> <span
                class="k">object</span> <span class="k">of</span> <span class="n">b</span>

  <span class="k">template</span> <span class="n">typeDeclPub</span><span class="p">(</span><span
                class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span> <span
                class="n">untyped</span> <span class="o">=</span>
    <span class="k">type</span> <span class="n">a</span><span class="o">*</span> <span class="o">=</span> <span
                class="k">ref</span> <span class="k">object</span> <span class="k">of</span> <span class="n">b</span>

  <span class="k">if</span> <span class="n">isExported</span><span class="p">:</span>
    <span class="n">result</span><span class="p">.</span><span class="n">add</span> <span class="n">getAst</span><span
                class="p">(</span><span class="n">typeDeclPub</span><span class="p">(</span><span
                class="n">typeName</span><span class="p">,</span> <span class="n">baseName</span><span
                class="p">))</span>
  <span class="k">else</span><span class="p">:</span>
    <span class="n">result</span><span class="p">.</span><span class="n">add</span> <span class="n">getAst</span><span
                class="p">(</span><span class="n">typeDecl</span><span class="p">(</span><span class="n">typeName</span><span
                class="p">,</span> <span class="n">baseName</span><span class="p">))</span>

  <span class="c"># echo treeRepr(body)</span>
  <span class="c"># --------------------</span>
  <span class="c"># StmtList</span>
  <span class="c">#   VarSection</span>
  <span class="c">#     IdentDefs</span>
  <span class="c">#       Ident !"name"</span>
  <span class="c">#       Ident !"string"</span>
  <span class="c">#       Empty</span>
  <span class="c">#     IdentDefs</span>
  <span class="c">#       Ident !"age"</span>
  <span class="c">#       Ident !"int"</span>
  <span class="c">#       Empty</span>
  <span class="c">#   MethodDef</span>
  <span class="c">#     Ident !"vocalize"</span>
  <span class="c">#     Empty</span>
  <span class="c">#     Empty</span>
  <span class="c">#     FormalParams</span>
  <span class="c">#       Ident !"string"</span>
  <span class="c">#     Empty</span>
  <span class="c">#     Empty</span>
  <span class="c">#     StmtList</span>
  <span class="c">#       StrLit ...</span>
  <span class="c">#   MethodDef</span>
  <span class="c">#     Ident !"age_human_yrs"</span>
  <span class="c">#     Empty</span>
  <span class="c">#     Empty</span>
  <span class="c">#     FormalParams</span>
  <span class="c">#       Ident !"int"</span>
  <span class="c">#     Empty</span>
  <span class="c">#     Empty</span>
  <span class="c">#     StmtList</span>
  <span class="c">#       DotExpr</span>
  <span class="c">#         Ident !"self"</span>
  <span class="c">#         Ident !"age"</span>

  <span class="c"># var declarations will be turned into object fields</span>
  <span class="kd">var</span> <span class="n">recList</span> <span class="o">=</span> <span
                class="n">newNimNode</span><span class="p">(</span><span class="n">nnkRecList</span><span
                class="p">)</span>

  <span class="c"># expected name of constructor</span>
  <span class="k">let</span> <span class="n">ctorName</span> <span class="o">=</span> <span
                class="n">newIdentNode</span><span class="p">(</span><span class="s">"new"</span> <span
                class="o">&amp;</span> <span class="o">$</span><span class="n">typeName</span><span class="p">)</span>

  <span class="c"># Iterate over the statements, adding `self: T`</span>
  <span class="c"># to the parameters of functions, unless the</span>
  <span class="c"># function is a constructor</span>
  <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">body</span><span
                class="p">.</span><span class="n">children</span><span class="p">:</span>
    <span class="k">case</span> <span class="n">node</span><span class="p">.</span><span class="n">kind</span><span
                class="p">:</span>

    <span class="k">of</span> <span class="n">nnkMethodDef</span><span class="p">,</span> <span
                class="n">nnkProcDef</span><span class="p">:</span>
      <span class="c"># check if it is the ctor proc</span>
      <span class="k">if</span> <span class="n">node</span><span class="p">.</span><span class="n">name</span><span
                class="p">.</span><span class="n">kind</span> <span class="o">!=</span> <span
                class="n">nnkAccQuoted</span> <span class="ow">and</span> <span class="n">node</span><span
                class="p">.</span><span class="n">name</span><span class="p">.</span><span
                class="n">basename</span> <span class="o">==</span> <span class="n">ctorName</span><span
                class="p">:</span>
        <span class="c"># specify the return type of the ctor proc</span>
        <span class="n">node</span><span class="p">.</span><span class="n">params</span><span class="o">[</span><span
                class="mi">0</span><span class="o">]</span> <span class="o">=</span> <span class="n">typeName</span>
      <span class="k">else</span><span class="p">:</span>
        <span class="c"># inject `self: T` into the arguments</span>
        <span class="n">node</span><span class="p">.</span><span class="n">params</span><span class="p">.</span><span
                class="n">insert</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span
                class="n">newIdentDefs</span><span class="p">(</span><span class="n">ident</span><span
                class="p">(</span><span class="s">"self"</span><span class="p">),</span> <span class="n">typeName</span><span
                class="p">))</span>
      <span class="n">result</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span
                class="n">node</span><span class="p">)</span>

    <span class="k">of</span> <span class="n">nnkVarSection</span><span class="p">:</span>
      <span class="c"># variables get turned into fields of the type.</span>
      <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">node</span><span
                class="p">.</span><span class="n">children</span><span class="p">:</span>
        <span class="n">recList</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span
                class="n">n</span><span class="p">)</span>

    <span class="k">else</span><span class="p">:</span>
      <span class="n">result</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span
                class="n">node</span><span class="p">)</span>

  <span class="c"># Inspect the tree structure:</span>
  <span class="c">#</span>
  <span class="c"># echo result.treeRepr</span>
  <span class="c"># --------------------</span>
  <span class="c"># StmtList</span>
  <span class="c">#   TypeSection</span>
  <span class="c">#     TypeDef</span>
  <span class="c">#       Ident !"Animal"</span>
  <span class="c">#       Empty</span>
  <span class="c">#       RefTy</span>
  <span class="c">#         ObjectTy</span>
  <span class="c">#           Empty</span>
  <span class="c">#           OfInherit</span>
  <span class="c">#             Ident !"RootObj"</span>
  <span class="c">#           Empty   &lt;= We want to replace this</span>
  <span class="c">#   MethodDef</span>
  <span class="c"># ...</span>

  <span class="n">result</span><span class="o">[</span><span class="mi">0</span><span class="o">][</span><span
                class="mi">0</span><span class="o">][</span><span class="mi">2</span><span class="o">][</span><span
                class="mi">0</span><span class="o">][</span><span class="mi">2</span><span class="o">]</span> <span
                class="o">=</span> <span class="n">recList</span>

  <span class="c"># Lets inspect the human-readable version of the output</span>
  <span class="c"># echo repr(result)</span>
  <span class="c"># Output:</span>
  <span class="c">#  type</span>
  <span class="c">#    Animal = ref object of RootObj</span>
  <span class="c">#      name: string</span>
  <span class="c">#      age: int</span>
  <span class="c">#</span>
  <span class="c">#  method vocalize(self: Animal): string {.base.} =</span>
  <span class="c">#    "..."</span>
  <span class="c">#</span>
  <span class="c">#  method age_human_yrs(self: Animal): int {.base.} =</span>
  <span class="c">#    self.age</span>
  <span class="c"># ...</span>
  <span class="c">#</span>
  <span class="c"># type</span>
  <span class="c">#   Rabbit = ref object of Animal</span>
  <span class="c">#</span>
  <span class="c"># proc newRabbit(name: string; age: int): Rabbit =</span>
  <span class="c">#   result = Rabbit(name: name, age: age)</span>
  <span class="c">#</span>
  <span class="c"># method vocalize(self: Rabbit): string =</span>
  <span class="c">#   "meep"</span>

<span class="c"># ---</span>

<span class="n">class</span> <span class="n">Animal</span> <span class="k">of</span> <span class="n">RootObj</span><span
                class="p">:</span>
  <span class="kd">var</span> <span class="n">name</span><span class="p">:</span> <span class="kt">string</span>
  <span class="kd">var</span> <span class="n">age</span><span class="p">:</span> <span class="kt">int</span>
  <span class="k">method</span> <span class="n">vocalize</span><span class="p">:</span> <span
                class="kt">string</span> <span class="p">{.</span><span class="n">base</span><span
                class="p">.}</span> <span class="o">=</span> <span class="s">"..."</span> <span class="c"># use `base` pragma to annotate base methods</span>
  <span class="k">method</span> <span class="n">age_human_yrs</span><span class="p">:</span> <span class="kt">int</span> <span
                class="p">{.</span><span class="n">base</span><span class="p">.}</span> <span class="o">=</span> <span
                class="n">self</span><span class="p">.</span><span class="n">age</span> <span class="c"># `self` is injected</span>
  <span class="k">proc </span><span class="nf">`$`</span><span class="p">:</span> <span class="kt">string</span> <span
                class="o">=</span> <span class="s">"animal:"</span> <span class="o">&amp;</span> <span
                class="n">self</span><span class="p">.</span><span class="n">name</span> <span
                class="o">&amp;</span> <span class="s">":"</span> <span class="o">&amp;</span> <span
                class="o">$</span><span class="n">self</span><span class="p">.</span><span class="n">age</span>

<span class="n">class</span> <span class="n">Dog</span> <span class="k">of</span> <span class="n">Animal</span><span
                class="p">:</span>
  <span class="k">method</span> <span class="n">vocalize</span><span class="p">:</span> <span
                class="kt">string</span> <span class="o">=</span> <span class="s">"woof"</span>
  <span class="k">method</span> <span class="n">age_human_yrs</span><span class="p">:</span> <span class="kt">int</span> <span
                class="o">=</span> <span class="n">self</span><span class="p">.</span><span class="n">age</span> <span
                class="o">*</span> <span class="mi">7</span>
  <span class="k">proc </span><span class="nf">`$`</span><span class="p">:</span> <span class="kt">string</span> <span
                class="o">=</span> <span class="s">"dog:"</span> <span class="o">&amp;</span> <span
                class="n">self</span><span class="p">.</span><span class="n">name</span> <span
                class="o">&amp;</span> <span class="s">":"</span> <span class="o">&amp;</span> <span
                class="o">$</span><span class="n">self</span><span class="p">.</span><span class="n">age</span>

<span class="n">class</span> <span class="n">Cat</span> <span class="k">of</span> <span class="n">Animal</span><span
                class="p">:</span>
  <span class="k">method</span> <span class="n">vocalize</span><span class="p">:</span> <span
                class="kt">string</span> <span class="o">=</span> <span class="s">"meow"</span>
  <span class="k">proc </span><span class="nf">`$`</span><span class="p">:</span> <span class="kt">string</span> <span
                class="o">=</span> <span class="s">"cat:"</span> <span class="o">&amp;</span> <span
                class="n">self</span><span class="p">.</span><span class="n">name</span> <span
                class="o">&amp;</span> <span class="s">":"</span> <span class="o">&amp;</span> <span
                class="o">$</span><span class="n">self</span><span class="p">.</span><span class="n">age</span>

<span class="n">class</span> <span class="n">Rabbit</span> <span class="k">of</span> <span class="n">Animal</span><span
                class="p">:</span>
  <span class="k">proc </span><span class="nf">newRabbit</span><span class="p">(</span><span class="n">name</span><span
                class="p">:</span> <span class="kt">string</span><span class="p">,</span> <span
                class="n">age</span><span class="p">:</span> <span class="kt">int</span><span class="p">)</span> <span
                class="o">=</span> <span class="c"># the constructor doesn't need a return type</span>
    <span class="n">result</span> <span class="o">=</span> <span class="n">Rabbit</span><span class="p">(</span><span
                class="n">name</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span
                class="n">age</span><span class="p">:</span> <span class="n">age</span><span class="p">)</span>
  <span class="k">method</span> <span class="n">vocalize</span><span class="p">:</span> <span
                class="kt">string</span> <span class="o">=</span> <span class="s">"meep"</span>
  <span class="k">proc </span><span class="nf">`$`</span><span class="p">:</span> <span class="kt">string</span> <span
                class="o">=</span> <span class="s">"rabbit:"</span> <span class="o">&amp;</span> <span
                class="n">self</span><span class="p">.</span><span class="n">name</span> <span
                class="o">&amp;</span> <span class="s">":"</span> <span class="o">&amp;</span> <span
                class="o">$</span><span class="n">self</span><span class="p">.</span><span class="n">age</span>

<span class="c"># ---</span>

<span class="kd">var</span> <span class="n">animals</span><span class="p">:</span> <span class="kt">seq</span><span
                class="o">[</span><span class="n">Animal</span><span class="o">]</span> <span class="o">=</span> <span
                class="o">@[]</span>
<span class="n">animals</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">Dog</span><span
                class="p">(</span><span class="n">name</span><span class="p">:</span> <span
                class="s">"Sparky"</span><span class="p">,</span> <span class="n">age</span><span
                class="p">:</span> <span class="mi">10</span><span class="p">))</span>
<span class="n">animals</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">Cat</span><span
                class="p">(</span><span class="n">name</span><span class="p">:</span> <span
                class="s">"Mitten"</span><span class="p">,</span> <span class="n">age</span><span
                class="p">:</span> <span class="mi">10</span><span class="p">))</span>

<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">animals</span><span
                class="p">:</span>
  <span class="n">echo</span> <span class="n">a</span><span class="p">.</span><span class="n">vocalize</span><span
                class="p">()</span>
  <span class="n">echo</span> <span class="n">a</span><span class="p">.</span><span class="n">age_human_yrs</span><span
                class="p">()</span>

<span class="k">let</span> <span class="n">r</span> <span class="o">=</span> <span class="n">newRabbit</span><span
                class="p">(</span><span class="s">"Fluffy"</span><span class="p">,</span> <span class="mi">3</span><span
                class="p">)</span>
<span class="n">echo</span> <span class="n">r</span><span class="p">.</span><span class="n">vocalize</span><span
                class="p">()</span>
<span class="n">echo</span> <span class="n">r</span><span class="p">.</span><span class="n">age_human_yrs</span><span
                class="p">()</span>
<span class="c"># `$` is not dynamically dispatched--if `r`'s type was</span>
<span class="c"># Animal instead of Rabbit, 'animal:…' would be printed.</span>
<span class="n">echo</span> <span class="n">r</span></code></pre>
    <pre><code class="language-console"><span class="gp">$</span> nim c -r oopmacro.nim
<span class="go">woof</span>
<span class="go">70</span>
<span class="go">meow</span>
<span class="go">10</span>
<span class="go">meep</span>
<span class="go">3</span>
<span class="go">rabbit:Fluffy:3</span></code></pre>

</article>

<div id=nextprev>
    <a class="text-icon disabled" href="https://please-enable-js/" id=arrow-prev>↽</a>
    <a class="text-icon disabled" href="https://please-enable-js/" id=arrow-next>⇁</a>
</div>

<footer>
    <li><a href="https://github.com/flaviut/nim-by-example">Contribute</a></li>
    <li
    ><a href="#" onclick="toggleDarkMode(); return false;">Toggle dark mode</a></li>

</footer>
</body>
</html>
